package com.isyscore.os.core.logger;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import com.isyscore.boot.logger.listener.AccessLoggerListener;
import com.isyscore.boot.logger.model.AccessLoggerInfo;
import com.isyscore.boot.login.cache.LoginUserHolder;
import com.isyscore.device.common.util.BeanMapper;
import com.isyscore.device.common.util.JsonMapper;
import com.isyscore.os.core.model.entity.OperationLog;
import com.isyscore.os.core.service.OperationLogService;
import com.isyscore.os.core.util.RequestUtils;
import com.isyscore.os.permission.entity.LoginVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author felixu
 * @since 2021.11.16
 */
@Component
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "isyscore.logger", value = "enabled", havingValue = "true")
@Slf4j
public class OperationLoggerListener implements AccessLoggerListener {

    private final OperationLogService operationLogService;

    private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 5,
            Runtime.getRuntime().availableProcessors() * 5, 5L,
            TimeUnit.MINUTES, new LinkedBlockingQueue<>(), ThreadFactoryBuilder.create().setNamePrefix("operation-log-")
            .setDaemon(true).build(), new ThreadPoolExecutor.DiscardPolicy());

    @Override
    public void onLogger(AccessLoggerInfo info) {
        Optional<HttpServletRequest> optional = RequestUtils.getHttpServletRequest();
        EXECUTOR.execute(() -> {
            HttpServletRequest request =null;
            try {
                OperationLogger logger = (OperationLogger) info;
                logger.setStrMethod(logger.getMethod().getName());
                logger.setStrTarget(logger.getTarget().getName());
                logger.setResponse(info.getResponse());
                logger.setDuration(Duration.between(logger.getRequestTime(), info.getEndTime()).toMillis());
                logger.setErrorMsg(null == info.getException() ? null : info.getException().getLocalizedMessage());
                // 添加其他信息
                if (optional.isPresent()) {
                    request= optional.get();
                    logger.setHttpHeaders(RequestUtils.getHeaders(request));
                    logger.setIp(RequestUtils.getIpAddress(request));
                    logger.setHttpMethod(request.getMethod());
                    logger.setUrl(request.getRequestURI());
                }
                OperationLog log = BeanMapper.map(logger, OperationLog.class);
                log.setParameters(JsonMapper.toAlwaysJson(logger.getParameters()));
                log.setResponse(JsonMapper.toAlwaysJson(logger.getResponse()));
                log.setExt(JsonMapper.toAlwaysJson(logger.getExt()));
                log.setHttpHeaders(JsonMapper.toAlwaysJson(logger.getHttpHeaders()));
                log.setOperator(Optional.ofNullable(LoginUserHolder.get()).map(LoginVO::getUserId).orElse("stranger"));
//                operationLogService.save(log);
            }catch(Exception e) {
                log.error("异常信息:", e);
//                log.error("请求地址:", request.getRequestURI());
//                Enumeration enu = request.getParameterNames();
//                while (enu.hasMoreElements()) {
//                    String paraName = (String) enu.nextElement();
//                    log.error("请求参数{}:{}", paraName, request.getParameter(paraName));
//                }
            }
        });
    }
}
